#include "Miro.h"
#include "Image.h"
#include <stdio.h>
#include <string.h>
#include <math.h>

#ifdef WIN32
// disable useless warnings
#pragma warning(disable:4996)
#endif

Image * g_image = 0;
HdrImage * g_hdrImage = 0;

Image::Image()
{
    m_pixels = 0;
    m_width = 1;
    m_height = 1;
	m_scaleFactor = 1;
}

Image::~Image()
{
    if (m_pixels)
        delete [] m_pixels;
}

void Image::resize(int width, int height)
{
    if (m_pixels)
        delete [] m_pixels;
    m_pixels = 0;
    m_pixels = new Pixel[width*height];
    memset(m_pixels, 0, width*height*sizeof(Pixel));
    m_width = width;
    m_height = height;
}

void Image::clear(const Vector3& c)
{
    // should be bg color
    for (int y=0; y<m_height; y++)
        for (int x=0; x<m_width; x++)
            setPixel(x, y, c);
}

// map floating point values to byte values for pixels
unsigned char Map(float r)
{
    float rMap = 255 * r;
    unsigned char c = rMap>255?255:(unsigned char)rMap;
    return c;
}

Image::Pixel Map(const HdrImage::HdrPixel &hp)
{
	Image::Pixel lp;
	lp.r = Map(hp.r);
	lp.g = Map(hp.g);
	lp.b = Map(hp.b);
	return lp;
}

Image::Pixel Map(const Vector3 &hp)
{
	Image::Pixel lp;
	lp.r = Map(hp.x);
	lp.g = Map(hp.y);
	lp.b = Map(hp.z);
	return lp;
}

unsigned char SigmoidMap(float r, float f, float b=1)
{
	float rMap = 255* b * r / (r + f);
    unsigned char c = rMap>255?255:(unsigned char)rMap;
    return c;
}

Image::Pixel SigmoidMap(const HdrImage::HdrPixel &hp, float f, float b=1)
{
	Image::Pixel lp;
	lp.r = SigmoidMap(hp.r, f, b);
	lp.g = SigmoidMap(hp.g, f, b);
	lp.b = SigmoidMap(hp.b, f, b);
	return lp;
}

Image::Pixel SigmoidMap(const Vector3 &hp, float f, float b=1)
{
	Image::Pixel lp;
	lp.r = SigmoidMap(hp.x, f, b);
	lp.g = SigmoidMap(hp.y, f, b);
	lp.b = SigmoidMap(hp.z, f, b);
	return lp;
}

void Image::setPixel(int x, int y, const Vector3& p)
{
    // do some tone mapping
    if (x >= 0 && x < m_width && y < m_height && y >= 0)
    {
        m_pixels[y*m_width+x].r = Map(p.x);
        m_pixels[y*m_width+x].g = Map(p.y);
        m_pixels[y*m_width+x].b = Map(p.z);
    }
}

void Image::setPixel(int x, int y, const Pixel& p)
{
    // do some tone mapping
    if (x >= 0 && x < m_width && y < m_height && y >= 0)
    {
        m_pixels[y*m_width+x]= p;
    }
}

bool Image::getPixel(int x, int y, Vector3& p) const
{
    if (x >= 0 && x < m_width && y < m_height && y >= 0)
    {
        p.x = m_pixels[y*m_width+x].r;
        p.y = m_pixels[y*m_width+x].g;
        p.z = m_pixels[y*m_width+x].b;

		return true;
    }
	return false;
}

bool Image::getPixel(int x, int y, Pixel &p) const
{
    if (x >= 0 && x < m_width && y < m_height && y >= 0)
    {
		p = m_pixels[y*m_width+x];
		return true;
	}
	return false;
}

bool Image::getRgb(float x, float y, Vector3 &rgb) const
{
    // normalized image coordinates
    if (x >= 0 && x <= 1 && y <= 1 && y >= 0)
    {
		/*int px = min(int(x*m_width), m_width-1);
		int py = min(int(y*m_height), m_height-1);*/
		Vector3 p11, p12, p21, p22;

		float fpx = std::max(0.0f,std::min((x*m_width)-.5f, m_width-1.0f));
		float fpy = std::max(0.0f,std::min((y*m_height)-.5f, m_height-1.0f));

		int px = (int) fpx;
		int py = (int) fpy;

		float fx = fpx - px;
		float fy = fpy - py;

		int py1 = std::min(py+1, m_height-1);
		int px1 = std::min(px+1, m_width-1);

		p11.x = m_pixels[py*m_width+px].r / m_scaleFactor;
		p11.y = m_pixels[py*m_width+px].g / m_scaleFactor;
        p11.z = m_pixels[py*m_width+px].b / m_scaleFactor;

		p12.x = m_pixels[py1*m_width+px].r / m_scaleFactor;
        p12.y = m_pixels[py1*m_width+px].g / m_scaleFactor;
        p12.z = m_pixels[py1*m_width+px].b / m_scaleFactor;

		p21.x = m_pixels[py*m_width+px1].r / m_scaleFactor;
		p21.y = m_pixels[py*m_width+px1].g / m_scaleFactor;
        p21.z = m_pixels[py*m_width+px1].b / m_scaleFactor;

		p22.x = m_pixels[py1*m_width+px1].r / m_scaleFactor;
        p22.y = m_pixels[py1*m_width+px1].g / m_scaleFactor;
        p22.z = m_pixels[py1*m_width+px1].b / m_scaleFactor;

		rgb.x = (1-fx)*(1-fy)*p11.x + (1-fx)*fy*p12.x + fx*(1-fy)*p21.x +fx*fy*p22.x;
		rgb.y = (1-fx)*(1-fy)*p11.y + (1-fx)*fy*p12.y + fx*(1-fy)*p21.y +fx*fy*p22.y;
		rgb.z = (1-fx)*(1-fy)*p11.z + (1-fx)*fy*p12.z + fx*(1-fy)*p21.z +fx*fy*p22.z;

		return true;
    }
	return false;
}


void Image::drawScanline(int y)
{
    glRasterPos2f(-1, -1 + 2*y / (float)m_height);
    glDrawPixels(m_width, 1, GL_RGB, GL_UNSIGNED_BYTE, &m_pixels[y*m_width]);
}

void Image::draw()
{
    for (int i = 0; i < m_height; i++)
        drawScanline(i);
}

void Image::writePPM(char* pcFile)
{
    writePPM(pcFile, (unsigned char*)m_pixels, m_width, m_height);
}

void Image::writePPM(char *pcFile, unsigned char *data, int width, int height)
{
    FILE *fp = fopen(pcFile, "wb");
    if (!fp)
        fprintf(stderr, "Couldn't open PPM file %s for writing\n", pcFile);
    else
    {
        fprintf(fp, "P6\n");
        fprintf(fp, "%d %d\n", width, height );
        fprintf(fp, "255\n" );

        // invert image
        int stride = width*3;
        for (int i = height-1; i >= 0; i--)
            fwrite(&data[stride*i], stride, 1, fp);
        fclose(fp);
    }
}

void Image::readPPM(char *pcFile)
{
    FILE *fp = fopen(pcFile, "rb");
    if (!fp)
        fprintf(stderr, "Couldn't open PPM file %s for reading\n", pcFile);
    else
    {
        int a = fgetc(fp);
        int b = fgetc(fp);
        fgetc(fp);

        if ((a != 'P') || (b != '6'))
            throw std::runtime_error("not a PPM image file.");

		char junk;
		char line[256]; // note: doesn't support lines longer than 256 chars
		line[0] = '#';
		while (line[0] == '#') // ignore comments - eventually want to check all the lines
		{
			fgets(&line[0], sizeof(line), fp);
		}
		sscanf(line, "%d %d%c", &m_width, &m_height, &junk);
        if ((m_width <= 0) || (m_height <= 0))
            throw std::runtime_error("invalid width or height.");

        fscanf(fp, "%f%c", &m_scaleFactor, &junk);

		// allocate pixels
		resize(m_width, m_height);

        // invert image
        int stride = m_width*3;
        for (int i = m_height-1; i >= 0; i--)
			fread(&((unsigned char*)m_pixels)[stride*i],stride,1,fp);
        fclose(fp);
    }
}




/////////////////////////////////////////////////////////////////////////////////////////////////////

HdrImage::HdrImage()
{
    m_hdrPixels = 0;
    m_width = 1;
    m_height = 1;
	m_scaleFactor = 1;
	m_toneMapStrength = 0.3;
}

HdrImage::~HdrImage()
{
    if (m_hdrPixels)
        delete [] m_hdrPixels;
}

void HdrImage::resize(int width, int height)
{
    if (m_hdrPixels)
        delete [] m_hdrPixels;
    m_hdrPixels = 0;
    m_hdrPixels = new HdrPixel[width*height];
    memset(m_hdrPixels, 0, width*height*sizeof(HdrPixel));
    m_width = width;
    m_height = height;

	m_image.resize(width, height);
}

void HdrImage::clear(const Vector3& c)
{
    // should be bg color
    for (int y=0; y<m_height; y++)
        for (int x=0; x<m_width; x++)
            setPixel(x, y, c);
}


void HdrImage::setPixel(int x, int y, const Vector3& p)
{
    setHdrPixel(x, y, p);
	setLdrPixel(x, y, p);
}

void HdrImage::setPixel(int x, int y, const HdrPixel& p)
{
    setHdrPixel(x, y, p);
	setLdrPixel(x, y, p);
}

void HdrImage::setHdrPixel(int x, int y, const Vector3& p)
{
    if (x >= 0 && x < m_width && y < m_height && y >= 0)
    {
        m_hdrPixels[(m_height-1-y)*m_width+x].r = p.x;
        m_hdrPixels[(m_height-1-y)*m_width+x].g = p.y;
        m_hdrPixels[(m_height-1-y)*m_width+x].b = p.z;
    }
}

void HdrImage::setHdrPixel(int x, int y, const HdrPixel& p)
{
    // do some tone mapping
    if (x >= 0 && x < m_width && y < m_height && y >= 0)
    {
        m_hdrPixels[(m_height-1-y)*m_width+x]= p;
    }
}

void HdrImage::setLdrPixel(int x, int y, const Vector3& p)
{
	m_image.setPixel(x, y, Map(p));
}

void HdrImage::setLdrPixel(int x, int y, const HdrPixel& hp)
{
	m_image.setPixel(x, y, Map(hp));
}

void HdrImage::setLdrPixel(int x, int y, const Image::Pixel& p)
{
    m_image.setPixel(x, y, p);
}

bool HdrImage::getHdrPixel(HdrPixel *pixels, int x, int y, HdrPixel &hp) const
{
    if (x >= 0 && x < m_width && y < m_height && y >= 0)
    {
		hp = pixels[(m_height-1-y)*m_width+x];
		return true;
	}
	return false;
}

bool HdrImage::getHdrPixel(int x, int y, HdrPixel &hp) const
{
    if (x >= 0 && x < m_width && y < m_height && y >= 0)
    {
		hp = m_hdrPixels[(m_height-1-y)*m_width+x];
		return true;
	}
	return false;
}

bool HdrImage::getHdrPixel(int x, int y, Vector3 &hp) const
{
    if (x >= 0 && x < m_width && y < m_height && y >= 0)
    {
        hp.x = m_hdrPixels[(m_height-1-y)*m_width+x].r;
        hp.y = m_hdrPixels[(m_height-1-y)*m_width+x].g;
        hp.z = m_hdrPixels[(m_height-1-y)*m_width+x].b;

		return true;
    }
	return false;
}

bool HdrImage::getLdrPixel(int x, int y, Image::Pixel &lp) const
{
	return m_image.getPixel(x, y, lp);
}

bool HdrImage::getLdrPixel(int x, int y, Vector3 &lp) const
{
    return m_image.getPixel(x, y, lp);
}

bool HdrImage::getRgb(float x, float y, Vector3 &rgb) const
{
    // normalized image coordinates
    if (x >= 0 && x <= 1 && y <= 1 && y >= 0)
    {
		/*
			int px = min(int(x*m_width), m_width-1);
			int py = min(int(y*m_height), m_height-1);

			rgb.x = m_hdrPixels[(m_height-1-py)*m_width+px].r;
			rgb.y = m_hdrPixels[(m_height-1-py)*m_width+px].g;
			rgb.z = m_hdrPixels[(m_height-1-py)*m_width+px].b;
		*/
		
		Vector3 p11, p12, p21, p22;

		float fpx = std::max(0.0f,std::min((x*m_width)-.5f, m_width-1.0f));
		float fpy = std::max(0.0f,std::min((y*m_height)-.5f, m_height-1.0f));

		int px = (int) fpx;
		int py = (int) fpy;

		float fx = fpx - px;
		float fy = fpy - py;

		int py1 = std::min(py+1, m_height-1);
		int px1 = std::min(px+1, m_width-1);

		p11.x = m_hdrPixels[(m_height-1-py)*m_width+px].r / m_scaleFactor;
		p11.y = m_hdrPixels[(m_height-1-py)*m_width+px].g / m_scaleFactor;
        p11.z = m_hdrPixels[(m_height-1-py)*m_width+px].b / m_scaleFactor;

		p12.x = m_hdrPixels[(m_height-1-py1)*m_width+px].r / m_scaleFactor;
        p12.y = m_hdrPixels[(m_height-1-py1)*m_width+px].g / m_scaleFactor;
        p12.z = m_hdrPixels[(m_height-1-py1)*m_width+px].b / m_scaleFactor;

		p21.x = m_hdrPixels[(m_height-1-py)*m_width+px1].r / m_scaleFactor;
		p21.y = m_hdrPixels[(m_height-1-py)*m_width+px1].g / m_scaleFactor;
        p21.z = m_hdrPixels[(m_height-1-py)*m_width+px1].b / m_scaleFactor;

		p22.x = m_hdrPixels[(m_height-1-py1)*m_width+px1].r / m_scaleFactor;
        p22.y = m_hdrPixels[(m_height-1-py1)*m_width+px1].g / m_scaleFactor;
        p22.z = m_hdrPixels[(m_height-1-py1)*m_width+px1].b / m_scaleFactor;

		rgb.x = (1-fx)*(1-fy)*p11.x + (1-fx)*fy*p12.x + fx*(1-fy)*p21.x +fx*fy*p22.x;
		rgb.y = (1-fx)*(1-fy)*p11.y + (1-fx)*fy*p12.y + fx*(1-fy)*p21.y +fx*fy*p22.y;
		rgb.z = (1-fx)*(1-fy)*p11.z + (1-fx)*fy*p12.z + fx*(1-fy)*p21.z +fx*fy*p22.z;

		return true;
    }
	return false;
}

void HdrImage::localToneMap(float strength)
{
	HdrPixel *blurred = new HdrPixel[m_width*m_height];
	blur(m_hdrPixels, blurred, 50, 2);

	// local tone map  to the LDR copy
	float l, lmin=999999, lmax = 0;
	float n, f = 0.5f, b;
	float white = 2.0f;
	HdrPixel bp, hp;
	Image::Pixel lp;
	for (int y=0; y<m_height; ++y)
	{
		for (int x=0; x<m_width; ++x)
		{
			getHdrPixel(blurred,x,y,bp);
			l = (bp.r + bp.g + bp.b)/3;
			lmax = std::max(l, lmax);
			lmin = std::min(l, lmin);
		}
	}
	for (int y=0; y<m_height; ++y)
	{
		for (int x=0; x<m_width; ++x)
		{
			getHdrPixel(x,y,hp);
			getHdrPixel(blurred,x,y,bp);
			l = (bp.r + bp.g + bp.b)/3;
			n = strength + (1-strength)*pow((lmax-l)/(lmax-lmin),1.4f);
			f = fabs(pow(l, n));
			b = (1 + l / (white*white)); // scaling to allow burnout
			setLdrPixel(x,y,SigmoidMap(hp, f, b));
		}
	}
	delete [] blurred;
}

void HdrImage::globalToneMap()
{
	HdrPixel hp;
	Image::Pixel p;
	float l, b;
	float white = 2.0;
	for (int y=0; y<m_height; ++y)
	{
		for (int x=0; x<m_width; ++x)
		{
			getHdrPixel(x,y,hp);
			l = (hp.r + hp.g + hp.b)/3;
			b = (1 + l / (white*white)); // scaling to allow burnout
			setLdrPixel(x,y,SigmoidMap(hp, 0.5, b));
		}
	}
}

void HdrImage::noToneMap()
{
	HdrPixel hp;
	Image::Pixel p;
	for (int y=0; y<m_height; ++y)
	{
		for (int x=0; x<m_width; ++x)
		{
			getHdrPixel(x,y,hp);
			setLdrPixel(x,y,Map(hp));
		}
	}

}

// assumes you've allocated dstPixels.
void HdrImage::blur(HdrPixel* srcPixels, HdrPixel* dstPixels, int radius, int times)
{
	HdrPixel *temp = new HdrPixel[m_width*m_height];
	HdrPixel *src = srcPixels;
	HdrPixel window(0,0,0);
	int x,y,i,j,k;


	for (int n=0; n<times; ++n)
	{
		// blur the image horizontally, into temp
		for (y=0; y<m_height; ++y)
		{
			window.set(0,0,0);
			for (i=0; i<2*radius+1; ++i)
			{
				j = std::max(y*m_width, y*m_width + i-radius);
				window.r += src[j].r;
				window.g += src[j].g;
				window.b += src[j].b;
			}
			for (x=0; x<m_width; ++x)
			{
				j = y*m_width + x;
				temp[j].r = window.r / (2*radius+1);
				temp[j].g = window.g / (2*radius+1);
				temp[j].b = window.b / (2*radius+1);

				// change the window for the next iteration
				j = std::max(y*m_width, y*m_width + x-radius);
				k = std::min((y+1)*m_width-1, y*m_width + x+radius+1);
				window.r += src[k].r - src[j].r;
				window.g += src[k].g - src[j].g;
				window.b += src[k].b - src[j].b;
			}
		}

		// now blur it vertically, back into hdrPixels
		for (x=0; x<m_width; ++x)
		{
			window.set(0,0,0);
			for (i=0; i<2*radius+1; ++i)
			{
				j = std::max(x, (i-radius)*m_width + x);
				window.r += temp[j].r;
				window.g += temp[j].g;
				window.b += temp[j].b;
			}
			for (y=0; y<m_height; ++y)
			{
				j = y*m_width + x;
				dstPixels[j].r = window.r / (2*radius+1);
				dstPixels[j].g = window.g / (2*radius+1);
				dstPixels[j].b = window.b / (2*radius+1);

				// change the window for the next iteration
				j = std::max(x, (y-radius)*m_width + x); // old pixel
				k = std::min((m_height-1)*m_width + x, (y+radius+1)*m_width + x); // new pixel
				window.r += temp[k].r - temp[j].r;
				window.g += temp[k].g - temp[j].g;
				window.b += temp[k].b - temp[j].b;
			}
		}
		src = dstPixels;
	}
	delete [] temp;
}

void HdrImage::blur(HdrPixel* hdrPixels, int radius, int times)
{
	blur(hdrPixels, hdrPixels, radius, times);
}

void HdrImage::blur(int radius, int times)
{
	blur(m_hdrPixels, m_hdrPixels, radius, times);
}


void HdrImage::bloom(HdrPixel* srcPixels, HdrPixel* dstPixels, bool selective, int times)
{
	HdrPixel *temp = new HdrPixel[m_width*m_height];
	HdrPixel *src = srcPixels;
	HdrPixel window(0,0,0);
	int x,y,i,j,k, px, py;

	const int size = 11;
	float pivot = size/2+1;
	float kernel[size];
	for (i=0; i<size; ++i)
		kernel[i] = pow((1. - fabs(pivot-i)/(pivot)),10.);
	float scale = 0;
	
	for (i=0; i<size; ++i)
	{
		for (j=0; j<size; ++j)
		{
			scale += kernel[i]*kernel[j];
		}
	}

	if (selective)	// only apply filter to neighborhood around saturated pixels.
					// note: this implementation can't use two 1d passes, so it's MUCH slower
	{
		float maxval = 0;
		for (int n=0; n<times; ++n)
		{
			// blur the image horizontally, into temp
			for (y=0; y<m_height; ++y)
			{
				for (x=0; x<m_width; ++x)
				{
					maxval = 0;
					window.set(0,0,0);
					for (i=0; i<size; ++i)
					{
						for (j=0; j<size; ++j)
						{
							px = std::max(0, std::min(m_width-1, x+i-size/2));
							py = std::max(0, std::min(m_height-1, y+j-size/2));
							k = py*m_width + px;
							window.r += kernel[i]*kernel[j]*src[k].r/scale;
							window.g += kernel[i]*kernel[j]*src[k].g/scale;
							window.b += kernel[i]*kernel[j]*src[k].b/scale;
							maxval = std::max(maxval, std::max(window.r, std::max(window.g, window.b)));
						}
					}
					k = y*m_width + x;
					if (maxval > 1)
					{
						temp[k].r = window.r;
						temp[k].g = window.g;
						temp[k].b = window.b;
					}
					else
					{
						temp[k].r = src[k].r;
						temp[k].g = src[k].g;
						temp[k].b = src[k].b;
					}
				}
			}
			for (y=0; y<m_height; ++y)
			{
				for (x=0; x<m_width; ++x)
				{
					k = y*m_width + x;
					dstPixels[k].r = temp[k].r;
					dstPixels[k].g = temp[k].g;
					dstPixels[k].b = temp[k].b;
				}
			}
			src = dstPixels;
		}
	}
	else // apply filter to whole image
	{
		for (int n=0; n<times; ++n)
		{
			// blur the image horizontally, into temp
			for (y=0; y<m_height; ++y)
			{
				for (x=0; x<m_width; ++x)
				{
					window.set(0,0,0);
					for (i=0; i<size; ++i)
					{
						px = std::max(0, std::min(m_width-1, x-size/2-1+i));
						k = y*m_width + px;
						window.r += kernel[i]*src[k].r;;
						window.g += kernel[i]*src[k].g;;
						window.b += kernel[i]*src[k].b;;
					}
					k = y*m_width + x;
					temp[k].r = window.r;
					temp[k].g = window.g;
					temp[k].b = window.b;
				}
			}

			// now blur it vertically, back into hdrPixels
			for (x=0; x<m_width; ++x)
			{
				for (y=0; y<m_height; ++y)
				{
					window.set(0,0,0);
					for (j=0; j<size; ++j)
					{
						py = std::max(0, std::min(m_height-1, y-size/2-1+j));
						k = py*m_width + x;
						window.r += kernel[j]*temp[k].r/scale;;
						window.g += kernel[j]*temp[k].g/scale;;
						window.b += kernel[j]*temp[k].b/scale;;
					}
					k = y*m_width + x;
					dstPixels[k].r = window.r;
					dstPixels[k].g = window.g;
					dstPixels[k].b = window.b;
				}
			}
			src = dstPixels;
		}
	}
	delete [] temp;
}

void HdrImage::bloom(HdrPixel* hdrPixels, bool selective, int times)
{
	bloom(hdrPixels, hdrPixels, selective, times);
}

void HdrImage::bloom(bool selective, int times)
{
	bloom(m_hdrPixels, m_hdrPixels, selective, times);
	noToneMap();
}

void HdrImage::drawScanline(int y)
{
	Image::Pixel *ldrPixels = getLdrPixels();
    glRasterPos2f(-1, -1 + 2*y / (float)m_height);
	glDrawPixels(m_width, 1, GL_RGB, GL_UNSIGNED_BYTE, &ldrPixels[y*m_width]);
}

void HdrImage::draw()
{
    for (int i = 0; i < m_height; i++)
        drawScanline(i);
}

void HdrImage::writePPM(char* pcFile)
{
	//m_image.resize(m_width, m_height);

	localToneMap(); // local tone map it
	m_image.writePPM(pcFile);
}

void HdrImage::writePPM(char *pcFile, unsigned char *data, int width, int height)
{
	m_image.writePPM(pcFile, data, width, height);
}

void HdrImage::writeHDR(char *pcFile)
{
    FILE *fp = fopen(pcFile, "wb");
    if (!fp)
        fprintf(stderr, "Couldn't open HDR file %s for writing\n", pcFile);
    else
    {
		rgbe_header_info info;
		sprintf(info.programtype, "#?RADIANCE");
		info.exposure = 1.;
		info.gamma = 1.;
		info.valid = 0xff;
		if (RGBE_WriteHeader(fp, m_width, m_height, &info) == RGBE_RETURN_FAILURE)
            throw std::runtime_error("error writing HDR image header.");

		if (RGBE_WritePixels(fp, (float *)m_hdrPixels, m_width*m_height) == RGBE_RETURN_FAILURE)
            throw std::runtime_error("error writing HDR image data.");

        fclose(fp);
    }
}

void HdrImage::readPPM(char *pcFile)
{
	m_image.readPPM(pcFile);
	m_height = m_image.height();
	m_width = m_image.width();
	resize(m_width, m_height);

	Vector3 rgb;
	for (int y=0; y<m_height; ++y)
	{
		for (int x=0; x<m_width; ++x)
		{
			getLdrPixel(x, y, rgb);
			setHdrPixel(x, y, rgb); // make copy of ldr image in hdr image
		}
	}
}


void HdrImage::readHDR(char *pcFile)
{
    FILE *fp = fopen(pcFile, "rb");
    if (!fp)
        fprintf(stderr, "Couldn't open HDR file %s for reading\n", pcFile);
    else
    {
		rgbe_header_info info;
		if (RGBE_ReadHeader(fp, &m_width, &m_height, &info) == RGBE_RETURN_FAILURE)
            throw std::runtime_error("not an HDR image file.");
        if ((m_width <= 0) || (m_height <= 0))
            throw std::runtime_error("invalid width or height.");
		resize(m_width, m_height);

		if (RGBE_ReadPixels_RLE(fp, (float *)m_hdrPixels, m_width, m_height) == RGBE_RETURN_FAILURE)
            throw std::runtime_error("error reading HDR image data.");

        fclose(fp);

		globalToneMap(); // make the LDR copy
    }
}
